﻿using CoreWCF;
using SD.Infrastructure.DTOBase;
using SlamDunk.MES.AppService.Maps;
using SlamDunk.MES.Domain.Entities.FoundationContext;
using SlamDunk.MES.Domain.Entities.ResourceContext;
using SlamDunk.MES.Domain.Entities.StockContext;
using SlamDunk.MES.Domain.IRepositories;
using SlamDunk.MES.Domain.Mediators;
using SlamDunk.MES.IAppService.DTOs.Inputs;
using SlamDunk.MES.IAppService.DTOs.Outputs.FoundationContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.StockContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.MES.ReportView.Models;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SlamDunk.MES.AppService.Implements
{
    /// <summary>
    /// 库存管理服务契约实现
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults = true)]
    public class StockManageContract : IStockManageContract
    {
        #region # 字段及构造器

        /// <summary>
        /// 领域服务中介者
        /// </summary>
        private readonly DomainServiceMediator _svcMediator;

        /// <summary>
        /// 仓储中介者
        /// </summary>
        private readonly RepositoryMediator _repMediator;

        /// <summary>
        /// 单元事务
        /// </summary>
        private readonly IUnitOfWorkMES _unitOfWork;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public StockManageContract(DomainServiceMediator svcMediator, RepositoryMediator repMediator, IUnitOfWorkMES unitOfWork)
        {
            this._svcMediator = svcMediator;
            this._repMediator = repMediator;
            this._unitOfWork = unitOfWork;
        }

        #endregion


        //命令部分

        #region # 创建物料批次 —— void CreateMaterialLot(Guid materialId, Guid supplierId...
        /// <summary>
        /// 创建物料批次
        /// </summary>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="supplierId">供应商Id</param>
        /// <param name="productionBatchNo">生产批号</param>
        /// <param name="producedDate">生产日期</param>
        /// <param name="guaranteePeriod">保质期</param>
        /// <param name="expiredDate">过期日期</param>
        /// <param name="receptionDate">接收日期</param>
        /// <param name="specification">规格</param>
        /// <param name="initialQuantity">初始数量</param>
        /// <param name="materialSourceType">物料来源</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        public void CreateMaterialLot(Guid materialId, Guid supplierId, string productionBatchNo, DateTime producedDate, TimeSpan guaranteePeriod, DateTime expiredDate, DateTime receptionDate, string specification, decimal? initialQuantity, MaterialSourceType materialSourceType, Guid? facilityId, string description)
        {
            #region # 验证

            bool existsMaterialLot = this._repMediator.MaterialLotRep.Exists(materialId, supplierId, productionBatchNo, producedDate, guaranteePeriod, expiredDate, receptionDate, specification);
            if (existsMaterialLot)
            {
                throw new InvalidOperationException("给定条件的物料批次已存在！");
            }

            #endregion

            Material material = this._repMediator.MaterialRep.Single(materialId);
            Enterprise supplier = this._repMediator.EnterpriseRep.Single(supplierId);
            facilityId ??= material.FacilityId;

            MaterialLot materialLot = new MaterialLot(material.Id, material.Number, material.Name, supplier.Id, supplier.Number, supplier.Name, productionBatchNo, producedDate, guaranteePeriod, expiredDate, receptionDate, specification, initialQuantity, materialSourceType, facilityId, description);

            this._unitOfWork.RegisterAdd(materialLot);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改物料批次 —— void UpdateMaterialLot(Guid materialLotId, Guid supplierId...
        /// <summary>
        /// 修改物料批次
        /// </summary>
        /// <param name="materialLotId">物料批次Id</param>
        /// <param name="supplierId">供应商Id</param>
        /// <param name="productionBatchNo">生产批号</param>
        /// <param name="producedDate">生产日期</param>
        /// <param name="guaranteePeriod">保质期</param>
        /// <param name="expiredDate">过期日期</param>
        /// <param name="receptionDate">接收日期</param>
        /// <param name="specification">规格</param>
        /// <param name="initialQuantity">初始数量</param>
        /// <param name="materialSourceType">物料来源</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        public void UpdateMaterialLot(Guid materialLotId, Guid supplierId, string productionBatchNo, DateTime producedDate, TimeSpan guaranteePeriod, DateTime expiredDate, DateTime receptionDate, string specification, decimal? initialQuantity, MaterialSourceType materialSourceType, Guid? facilityId, string description)
        {
            Enterprise supplier = this._repMediator.EnterpriseRep.Single(supplierId);

            MaterialLot materialLot = this._unitOfWork.Resolve<MaterialLot>(materialLotId);
            materialLot.UpdateInfo(supplierId, supplier.Number, supplier.Name, productionBatchNo, producedDate, guaranteePeriod, expiredDate, receptionDate, specification, initialQuantity, materialSourceType, facilityId, description);

            this._unitOfWork.RegisterSave(materialLot);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 生成物料条码 —— string GenerateMaterialBacode(Guid materialId...
        /// <summary>
        /// 生成物料条码
        /// </summary>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="materialLotId">物料批次Id</param>
        /// <returns>物料条码编号</returns>
        public string GenerateMaterialBacode(Guid materialId, Guid? materialLotId)
        {
            Material material = this._repMediator.MaterialRep.Single(materialId);
            MaterialLot materialLot = materialLotId.HasValue
                ? this._repMediator.MaterialLotRep.Single(materialLotId.Value)
                : null;

            #region # 验证

            if (material.MaterialBarcodeSetting == null)
            {
                throw new InvalidOperationException("物料定义未配置物料条码设置！");
            }
            if (material.MaterialBarcodeSetting.BarcodeMode != BarcodeMode.Unique)
            {
                throw new InvalidOperationException("物料定义未配置唯一码模式！");
            }

            #endregion

            string materialBarcodeNo = this._svcMediator.NumberSvc.GenerateMaterialBarcodeNo();
            Guid? facilityId = materialLot?.FacilityId ?? material.FacilityId;
            decimal quantity;

            #region # 条码量判断

            if (material.MaterialBarcodeSetting.BarcodeUnit == material.MaterialPack.MaxPack)
            {
                quantity = material.MaterialPack.MaxPackCoefficient!.Value * material.MaterialPack.MinPackCoefficient;
            }

            else if (material.MaterialBarcodeSetting.BarcodeUnit == material.MaterialPack.MinPack)
            {
                quantity = material.MaterialPack.MinPackCoefficient;
            }
            else
            {
                quantity = 1;
            }

            #endregion

            MaterialBarcode materialBarcode = new MaterialBarcode(materialBarcodeNo, materialId, materialLotId, facilityId, quantity);

            this._unitOfWork.RegisterAdd(materialBarcode);
            this._unitOfWork.Commit();

            return materialBarcode.Number;
        }
        #endregion

        #region # 批量生成物料条码 —— IEnumerable<string> GenerateMaterialBacodes(Guid...
        /// <summary>
        /// 批量生成物料条码
        /// </summary>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="materialLotId">物料批次Id</param>
        /// <param name="count">条码数量</param>
        /// <returns>物料条码编号列表</returns>
        public IEnumerable<string> GenerateMaterialBacodes(Guid materialId, Guid? materialLotId, int count)
        {
            Material material = this._repMediator.MaterialRep.Single(materialId);
            MaterialLot materialLot = materialLotId.HasValue
                ? this._repMediator.MaterialLotRep.Single(materialLotId.Value)
                : null;

            #region # 验证

            if (material.MaterialBarcodeSetting == null)
            {
                throw new InvalidOperationException("物料定义未配置物料条码设置！");
            }
            if (material.MaterialBarcodeSetting.BarcodeMode != BarcodeMode.Unique)
            {
                throw new InvalidOperationException("物料定义未配置唯一码模式！");
            }

            #endregion

            string[] materialBarcodeNos = this._svcMediator.NumberSvc.GenerateMaterialBarcodeNos(count);
            Guid? facilityId = materialLot?.FacilityId ?? material.FacilityId;
            decimal quantity;

            #region # 条码物料数量判断

            if (material.MaterialBarcodeSetting.BarcodeUnit == material.MaterialPack.MaxPack)
            {
                quantity = material.MaterialPack.MaxPackCoefficient!.Value * material.MaterialPack.MinPackCoefficient;
            }

            else if (material.MaterialBarcodeSetting.BarcodeUnit == material.MaterialPack.MinPack)
            {
                quantity = material.MaterialPack.MinPackCoefficient;
            }
            else
            {
                quantity = 1;
            }

            #endregion

            IEnumerable<MaterialBarcode> materialBarcodes =
                from materialBarcodeNo in materialBarcodeNos
                select new MaterialBarcode(materialBarcodeNo, materialId, materialLotId, facilityId, quantity);

            this._unitOfWork.RegisterAddRange(materialBarcodes);
            this._unitOfWork.Commit();

            return materialBarcodeNos;
        }
        #endregion

        #region # 结转库存 —— void SettleStock(Guid materialId, Guid? materialLotId...
        /// <summary>
        /// 结转库存
        /// </summary>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="materialLotId">物料批次Id</param>
        /// <param name="materialLotParam">物料批次参数模型</param>
        /// <param name="storageLocationType">储存位置类型</param>
        /// <param name="storageLocationId">储存位置Id</param>
        /// <param name="storageLocationName">储存位置名称</param>
        /// <param name="settledDate">结转日期</param>
        /// <param name="quantity">数量</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        public void SettleStock(Guid materialId, Guid? materialLotId, MaterialLotParam materialLotParam, StorageLocationType storageLocationType, string storageLocationId, string storageLocationName, DateTime settledDate, decimal quantity, Guid? facilityId, string description)
        {
            Guid? materialLotId_ = null;

            #region # 物料批次处理

            if (materialLotId.HasValue)
            {
                materialLotId_ = materialLotId.Value;
            }
            else if (materialLotParam != null)
            {
                MaterialLot materialLot = this._repMediator.MaterialLotRep.SingleOrDefault(materialId, materialLotParam.supplierId, materialLotParam.productionBatchNo, materialLotParam.producedDate, materialLotParam.guaranteePeriod, materialLotParam.expiredDate, materialLotParam.receptionDate, materialLotParam.specification);
                if (materialLot == null)
                {
                    Material material = this._repMediator.MaterialRep.Single(materialId);
                    Enterprise supplier = this._repMediator.EnterpriseRep.Single(materialLotParam.supplierId);
                    materialLot = new MaterialLot(material.Id, material.Number, material.Name, supplier.Id, supplier.Number, supplier.Name, materialLotParam.productionBatchNo, materialLotParam.producedDate, materialLotParam.guaranteePeriod, materialLotParam.expiredDate, materialLotParam.receptionDate, materialLotParam.specification, quantity, materialLotParam.materialSourceType, material.FacilityId, null);

                    this._unitOfWork.RegisterAdd(materialLot);
                }

                materialLotId_ = materialLot.Id;
            }

            #endregion

            StockSettlement stockSettlement = new StockSettlement(materialId, materialLotId_, storageLocationType, storageLocationId, storageLocationName, settledDate, quantity, facilityId, description);

            this._unitOfWork.RegisterAdd(stockSettlement);
            this._unitOfWork.Commit();
        }
        #endregion


        //查询部分

        #region # 分页获取物料批次列表 —— PageModel<MaterialLotInfo> GetMaterialLotsByPage(string keywords...
        /// <summary>
        /// 分页获取物料批次列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="supplierId">供应商Id</param>
        /// <param name="startProducedDate">生产日期开始</param>
        /// <param name="endProducedDate">生产日期结束</param>
        /// <param name="startExpiredDate">过期日期开始</param>
        /// <param name="endExpiredDate">过期日期结束</param>
        /// <param name="startReceptionDate">接收日期开始</param>
        /// <param name="endReceptionDate">接收日期结束</param>
        /// <param name="materialSourceType">物料来源类型</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>物料批次列表</returns>
        public PageModel<MaterialLotInfo> GetMaterialLotsByPage(string keywords, Guid? materialId, Guid? supplierId, DateTime? startProducedDate, DateTime? endProducedDate, DateTime? startExpiredDate, DateTime? endExpiredDate, DateTime? startReceptionDate, DateTime? endReceptionDate, MaterialSourceType? materialSourceType, Guid? facilityId, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<MaterialLot> materialLots = this._repMediator.MaterialLotRep.FindByPage(keywords, materialId, supplierId, startProducedDate, endProducedDate, startExpiredDate, endExpiredDate, startReceptionDate, endReceptionDate, materialSourceType, relatedFacilityIds, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> facilityIds = materialLots.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<MaterialLotInfo> materialLotInfos = materialLots.Select(x => x.ToDTO(facilityInfos));

            return new PageModel<MaterialLotInfo>(materialLotInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取物料条码列表 —— PageModel<MaterialBarcodeInfo> GetMaterialBarcodesByPage(Guid?...
        /// <summary>
        /// 分页获取物料条码列表
        /// </summary>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="materialLotId">物料批次Id</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>物料条码列表</returns>
        public PageModel<MaterialBarcodeInfo> GetMaterialBarcodesByPage(Guid? materialId, Guid? materialLotId, Guid? facilityId, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<MaterialBarcode> materialBarcodes = this._repMediator.MaterialBarcodeRep.FindByPage(materialId, materialLotId, relatedFacilityIds, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> materialIds = materialBarcodes.Select(x => x.MaterialId);
            IEnumerable<Guid> materialLotIds = materialBarcodes.Where(x => x.MaterialLotId.HasValue).Select(x => x.MaterialLotId.Value);
            IEnumerable<Guid> facilityIds = materialBarcodes.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, MaterialInfo> materialInfos = this._repMediator.MaterialRep.Find(materialIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, MaterialLotInfo> materialLotInfos = this._repMediator.MaterialLotRep.Find(materialLotIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<MaterialBarcodeInfo> materialBarcodeInfos = materialBarcodes.Select(x => x.ToDTO(materialInfos, materialLotInfos, facilityInfos));

            return new PageModel<MaterialBarcodeInfo>(materialBarcodeInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 根据编号获取物料条码字典 —— IDictionary<string, MaterialBarcodeInfo> GetMaterialBarcodesByNo(...
        /// <summary>
        /// 根据编号获取物料条码字典
        /// </summary>
        /// <param name="materialBarcodeNos">物料条码编号集</param>
        /// <returns>物料条码字典</returns>
        public IDictionary<string, MaterialBarcodeInfo> GetMaterialBarcodesByNo(IEnumerable<string> materialBarcodeNos)
        {
            #region # 验证

            materialBarcodeNos = materialBarcodeNos?.Distinct().ToArray() ?? Array.Empty<string>();
            if (!materialBarcodeNos.Any())
            {
                return new Dictionary<string, MaterialBarcodeInfo>();
            }

            #endregion

            IDictionary<string, MaterialBarcode> materialBarcodes = this._repMediator.MaterialBarcodeRep.Find(materialBarcodeNos);

            IEnumerable<Guid> materialIds = materialBarcodes.Values.Select(x => x.MaterialId);
            IEnumerable<Guid> materialLotIds = materialBarcodes.Values.Where(x => x.MaterialLotId.HasValue).Select(x => x.MaterialLotId.Value);
            IEnumerable<Guid> facilityIds = materialBarcodes.Values.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, MaterialInfo> materialInfos = this._repMediator.MaterialRep.Find(materialIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, MaterialLotInfo> materialLotInfos = this._repMediator.MaterialLotRep.Find(materialLotIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IDictionary<string, MaterialBarcodeInfo> materialBarcodeInfos = materialBarcodes.ToDictionary(x => x.Key, x => x.Value.ToDTO(materialInfos, materialLotInfos, facilityInfos));
            foreach (string materialBarcodeNo in materialBarcodeNos)
            {
                if (!materialBarcodeInfos.ContainsKey(materialBarcodeNo))
                {
                    materialBarcodeInfos.Add(materialBarcodeNo, null);
                }
            }

            return materialBarcodeInfos;
        }
        #endregion

        #region # 分页获取库存结转记录列表 —— PageModel<StockSettlementInfo> GetStockSettlementsByPage(...
        /// <summary>
        /// 分页获取库存结转记录列表
        /// </summary>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="materialLotId">物料批次Id</param>
        /// <param name="storageLocationType">储存位置类型</param>
        /// <param name="storageLocationId">储存位置Id</param>
        /// <param name="startSettledDate">结转日期开始</param>
        /// <param name="endSettledDate">结转日期结束</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>库存结转记录列表</returns>
        public PageModel<StockSettlementInfo> GetStockSettlementsByPage(Guid? materialId, Guid? materialLotId, StorageLocationType? storageLocationType, string storageLocationId, DateTime? startSettledDate, DateTime? endSettledDate, Guid? facilityId, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<StockSettlement> stockSettlements = this._repMediator.StockSettlementRep.FindByPage(materialId, materialLotId, storageLocationType, storageLocationId, startSettledDate, endSettledDate, relatedFacilityIds, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> materialIds = stockSettlements.Select(x => x.MaterialId);
            IEnumerable<Guid> materialLotIds = stockSettlements.Where(x => x.MaterialLotId.HasValue).Select(x => x.MaterialLotId.Value);
            IEnumerable<Guid> facilityIds = stockSettlements.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, MaterialInfo> materialInfos = this._repMediator.MaterialRep.Find(materialIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, MaterialLotInfo> materialLotInfos = this._repMediator.MaterialLotRep.Find(materialLotIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<StockSettlementInfo> stockSettlementInfos = stockSettlements.Select(x => x.ToDTO(materialInfos, materialLotInfos, facilityInfos));

            return new PageModel<StockSettlementInfo>(stockSettlementInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取物料库存列表 —— PageModel<MaterialStockInfo> GetMaterialStocksByPage(string keywords...
        /// <summary>
        /// 分页获取物料库存列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="materialLotId">物料批次Id</param>
        /// <param name="supplierId">供应商Id</param>
        /// <param name="storageLocationType">储存位置类型</param>
        /// <param name="storageLocationId">储存位置Id</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>物料库存列表</returns>
        public PageModel<MaterialStockInfo> GetMaterialStocksByPage(string keywords, Guid? materialId, Guid? materialLotId, Guid? supplierId, StorageLocationType? storageLocationType, string storageLocationId, Guid? facilityId, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<MaterialStockInfo> materialStocks = this._repMediator.StockSettlementRep.GetMaterialStocksByPage(keywords, materialId, materialLotId, supplierId, storageLocationType, storageLocationId, relatedFacilityIds, pageIndex, pageSize, out int rowCount, out int pageCount);

            //保质期TimeSpan处理
            foreach (MaterialStockInfo materialStock in materialStocks)
            {
                materialStock.GuaranteePeriod = materialStock.GuaranteePeriodTicks.HasValue
                    ? TimeSpan.FromTicks(materialStock.GuaranteePeriodTicks.Value)
                    : (TimeSpan?)null;
            }

            return new PageModel<MaterialStockInfo>(materialStocks, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取出/入库记录列表 —— PageModel<BoundRecordInfo> GetBoundRecordsByPage(Guid? materialId...
        /// <summary>
        /// 分页获取出/入库记录列表
        /// </summary>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="materialLotId">物料批次Id</param>
        /// <param name="directionType">出/入库方向类型</param>
        /// <param name="storageLocationType">储存位置类型</param>
        /// <param name="storageLocationId">储存位置Id</param>
        /// <param name="stockOrderClassId">库存单据类Id</param>
        /// <param name="stockOrderId">库存单据Id</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>出/入库记录列表</returns>
        public PageModel<BoundRecordInfo> GetBoundRecordsByPage(Guid? materialId, Guid? materialLotId, StockDirectionType? directionType, StorageLocationType? storageLocationType, string storageLocationId, Guid? stockOrderClassId, Guid? stockOrderId, Guid? facilityId, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<BoundRecord> boundRecords = this._repMediator.BoundRecordRep.FindByPage(materialId, materialLotId, directionType, storageLocationType, storageLocationId, stockOrderClassId, stockOrderId, relatedFacilityIds, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> materialIds = boundRecords.Select(x => x.MaterialId);
            IEnumerable<Guid> materialLotIds = boundRecords.Where(x => x.MaterialLotId.HasValue).Select(x => x.MaterialLotId.Value);
            IEnumerable<Guid> facilityIds = boundRecords.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, MaterialInfo> materialInfos = this._repMediator.MaterialRep.Find(materialIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, MaterialLotInfo> materialLotInfos = this._repMediator.MaterialLotRep.Find(materialLotIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<BoundRecordInfo> boundRecordInfos = boundRecords.Select(x => x.ToDTO(materialInfos, materialLotInfos, facilityInfos));

            return new PageModel<BoundRecordInfo>(boundRecordInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion
    }
}
